home *** CD-ROM | disk | FTP | other *** search
- /*
- * cd_commands.c: CD-ROM drive specific commands
- *
- * This is based on the file that NeXT included in
- * /NextDeveloper/Examples/UNIX/SCSI_CD,
- * done by James C. Lee at NeXT, Sep 1991.
- * It has been changed "just a bit" by Garance Alistair Drosehn/March 1994.
- *
- */
-
- #define CD_DEBUG2
-
- #import <libc.h>
- #import <objc/objc.h>
- #import <c.h>
- #import "cd_commands.h"
- #import "cd_cmdsint.h" /* structs internal to cd_commands */
- #import "scsi_commands.h"
-
- /**************************************************************************
- * do_eject_1b
- *
- */
- int
- do_eject_1b(int fd, struct timeval * tvp, struct esense_reply * erp)
- {
- struct scsi_req sr;
- struct start_stop_1B_cmd *sscp;
- int err;
-
- bzero((char *)&sr, sizeof(sr));
-
- sscp = (struct start_stop_1B_cmd *) & sr.sr_cdb;
- sscp->ssc_opcode = C6OP_STARTSTOP;
- sscp->ssc_imm = 0; /* status will be returned after the
- * operation is completed */
- sscp->ssc_loej = 1; /* eject when spin down (scc_start=0) */
- sscp->ssc_start = 0; /* spin down */
-
- sr.sr_addr = NULL;
- sr.sr_dma_max = 0; /* don't really do I/O to memory */
- sr.sr_ioto = 10; /* time out in 10 seconds */
- sr.sr_dma_dir = SR_DMA_RD;
-
- err = ioctl(fd, SDIOCSRQ, &sr);
-
- *tvp = sr.sr_exec_time;
-
- if (sr.sr_dma_xfr != 0)
- fatal("scsi driver did transfer: %d", sr.sr_dma_xfr);
-
- *erp = sr.sr_esense;
- return err | sr.sr_io_status;
- }
-
-
- /**************************************************************************
- * do_spinup_1b
- *
- * same command as do_eject, except that sscp->ssc_start=1 and
- * sscp->ssc_loej=0
- */
- int
- do_spinup_1b(int fd, struct timeval * tvp, struct esense_reply * erp)
- {
- struct scsi_req sr;
- struct start_stop_1B_cmd *sscp;
- int err;
-
- bzero((char *)&sr, sizeof(sr));
-
- sscp = (struct start_stop_1B_cmd *) & sr.sr_cdb;
- sscp->ssc_opcode = C6OP_STARTSTOP;
- sscp->ssc_imm = 0; /* status will be returned after the
- * operation is completed */
- sscp->ssc_loej = 0;
- sscp->ssc_start = 1; /* spin up */
-
- sr.sr_addr = NULL;
- sr.sr_dma_max = 0; /* don't really do I/O to memory */
- sr.sr_ioto = 10; /* time out in 10 seconds */
- sr.sr_dma_dir = SR_DMA_RD;
-
- err = ioctl(fd, SDIOCSRQ, &sr);
-
- *tvp = sr.sr_exec_time;
-
- if (sr.sr_dma_xfr != 0)
- fatal("scsi driver did transfer: %d", sr.sr_dma_xfr);
-
- *erp = sr.sr_esense;
- return err | sr.sr_io_status;
- }
-
-
- /**************************************************************************
- * do_stopunit_1b
- *
- * same command as do_eject_1b, except that sscp->ssc_loej=0
- * because the caddy should not be ejected.
- */
- int
- do_stopunit_1b(int fd, struct timeval * tvp, struct esense_reply * erp)
- {
- struct scsi_req sr;
- struct start_stop_1B_cmd *sscp;
- int err;
-
- bzero((char *)&sr, sizeof(sr));
-
- sscp = (struct start_stop_1B_cmd *) & sr.sr_cdb;
- sscp->ssc_opcode = C6OP_STARTSTOP;
- sscp->ssc_imm = 0; /* status will be returned after the
- * operation is completed */
- sscp->ssc_loej = 0; /* do not eject when spin down (scc_start=0) */
- sscp->ssc_start = 0; /* spin down */
-
- sr.sr_addr = NULL;
- sr.sr_dma_max = 0; /* don't really do I/O to memory */
- sr.sr_ioto = 10; /* time out in 10 seconds */
- sr.sr_dma_dir = SR_DMA_RD;
-
- err = ioctl(fd, SDIOCSRQ, &sr);
-
- *tvp = sr.sr_exec_time;
-
- if (sr.sr_dma_xfr != 0)
- fatal("scsi driver did transfer: %d", sr.sr_dma_xfr);
-
- *erp = sr.sr_esense;
- return err | sr.sr_io_status;
- }
-
-
- /**************************************************************************
- * do_pauseaudio_4b
- */
- int
- do_pauseaudio_4b(int fd, int pause, struct esense_reply * erp)
- {
- struct scsi_req sr;
- struct pause_4b_cmd *pp;
- int err;
-
- bzero((char *)&sr, sizeof(sr));
-
- pp = (struct pause_4b_cmd *) & sr.sr_cdb;
- pp->p_op_code = C10OP_PAUSE_4B;
- pp->p_resume = !pause; /* resume = not(pause) */
-
- sr.sr_addr = NULL;
- sr.sr_dma_max = 0;
- sr.sr_ioto = 5; /* time out in 5 seconds */
- sr.sr_dma_dir = SR_DMA_RD;
-
- err = ioctl(fd, SDIOCSRQ, &sr);
-
- if (sr.sr_dma_xfr != 0)
- fatal("scsi driver did transfer: %d", sr.sr_dma_xfr);
-
- *erp = sr.sr_esense;
- return err | sr.sr_io_status;
- }
-
-
- /**************************************************************************
- * do_pauseaudio_c5
- *
- * this command implements the same capability as do_pauseaudio_4b,
- * but the x'c5' opcode is the the standardized one. This works on
- * the CD-ROM drive that NeXT sold, but not on other CD-ROM drives.
- */
- int
- do_pauseaudio_c5(int fd, int pause, struct esense_reply * erp)
- {
- struct scsi_req sr;
- struct pause_c5_cmd *pp;
- int err;
-
- bzero((char *)&sr, sizeof(sr));
-
- pp = (struct pause_c5_cmd *) & sr.sr_cdb;
- pp->p_op_code = C10OP_PAUSE_C5;
- pp->p_pause = pause;
-
- sr.sr_addr = NULL;
- sr.sr_dma_max = 0;
- sr.sr_ioto = 5; /* time out in 5 seconds */
- sr.sr_dma_dir = SR_DMA_RD;
-
- err = ioctl(fd, SDIOCSRQ, &sr);
-
- if (sr.sr_dma_xfr != 0)
- fatal("scsi driver did transfer: %d", sr.sr_dma_xfr);
-
- *erp = sr.sr_esense;
- return err | sr.sr_io_status;
- }
-
-
- /**************************************************************************
- * do_preventremoval_1e
- *
- * prevent (or allow) medium removal. ie, disable (enable) the
- * button on the front of the CD-ROM drive.
- */
- int
- do_preventremoval_1e(int fd, int prevent, struct esense_reply * erp)
- {
- struct scsi_req sr;
- struct prevent_removal_1e_cmd *pp;
- int err;
-
- bzero((char *)&sr, sizeof(sr));
-
- pp = (struct prevent_removal_1e_cmd *) & sr.sr_cdb;
- pp->par_op_code = C6OP_PREVENT_REMOVAL_1E;
- pp->par_prevent = prevent; /* 0 = allow, 1 = prevent */
-
- sr.sr_addr = NULL;
- sr.sr_dma_max = 0;
- sr.sr_ioto = 5; /* time out in 5 seconds */
- sr.sr_dma_dir = SR_DMA_RD;
-
- err = ioctl(fd, SDIOCSRQ, &sr);
-
- if (sr.sr_dma_xfr != 0)
- fatal("scsi driver did transfer: %d", sr.sr_dma_xfr);
-
- *erp = sr.sr_esense;
- return err | sr.sr_io_status;
- }
-
-
- /**************************************************************************
- * do_rezerounit_01
- */
- int
- do_rezerounit_01(int fd, struct esense_reply * erp)
- {
- struct scsi_req sr;
- struct rezero_unit_01_cmd *rz;
- int err;
-
- bzero((char *)&sr, sizeof(sr));
-
- rz = (struct rezero_unit_01_cmd *) & sr.sr_cdb;
- rz->rzu_opcode = C6OP_REZEROUNIT_01;
-
- sr.sr_addr = NULL;
- sr.sr_dma_max = 0;
- sr.sr_ioto = 5; /* time out in 5 seconds */
- sr.sr_dma_dir = SR_DMA_RD;
-
- err = ioctl(fd, SDIOCSRQ, &sr);
-
- if (sr.sr_dma_xfr != 0)
- fatal("scsi driver did transfer: %d", sr.sr_dma_xfr);
-
- *erp = sr.sr_esense;
- return err | sr.sr_io_status;
- }
-
-
- /**************************************************************************
- * do_playaudio_c8
- */
- int
- do_playaudio_c8(int fd, int lba, int length, struct esense_reply * erp)
- {
- struct scsi_req sr;
- struct playaudio_c8_cmd *pap;
- int err;
-
- bzero((char *)&sr, sizeof(sr));
-
- pap = (struct playaudio_c8_cmd *) & sr.sr_cdb;
- pap->pa_op_code = C6OP_PLAYAUDIO_C8;
- SET_4BYTE_UINT(pap->pa_lba, lba); /* block to play audio from */
- SET_2BYTE_UINT(pap->pa_length, length); /* length to play */
-
- sr.sr_addr = NULL;
- sr.sr_dma_max = 0;
- sr.sr_ioto = 10; /* time out in 10 seconds */
- sr.sr_dma_dir = SR_DMA_RD;
-
- err = ioctl(fd, SDIOCSRQ, &sr);
-
- if (sr.sr_dma_xfr != 0)
- fatal("scsi driver did transfer: %d", sr.sr_dma_xfr);
-
- *erp = sr.sr_esense;
- return err | sr.sr_io_status;
- }
-
-
- /**************************************************************************
- * do_playaudio_msf_47
- */
- int
- do_playaudio_msf_47(int fd, struct pa_msf startmsf, struct pa_msf endmsf,
- struct esense_reply * erp)
- {
- struct scsi_req sr;
- struct playaudio_msf_47_cmd *pap;
- int err;
-
- bzero((char *)&sr, sizeof(sr));
-
- pap = (struct playaudio_msf_47_cmd *) & sr.sr_cdb;
- pap->pam_op_code = C10OP_PLAYAUDIO_MSF_47;
- pap->pam_start_min = startmsf.min;
- pap->pam_start_sec = startmsf.sec;
- pap->pam_start_frame = startmsf.frame;
- pap->pam_end_min = endmsf.min;
- pap->pam_end_sec = endmsf.sec;
- pap->pam_end_frame = endmsf.frame;
-
- sr.sr_addr = NULL;
- sr.sr_dma_max = 0;
- sr.sr_ioto = 10; /* time out in 10 seconds */
- sr.sr_dma_dir = SR_DMA_RD;
-
- err = ioctl(fd, SDIOCSRQ, &sr);
-
- if (sr.sr_dma_xfr != 0)
- fatal("scsi driver did transfer: %d", sr.sr_dma_xfr);
-
- *erp = sr.sr_esense;
- return err | sr.sr_io_status;
- }
-
-
- /**************************************************************************
- * do_readtoc_43
- *
- * read in the entire table-of-contents of an audio CD, and return
- * to the user in a platform-independent format.
- */
- int
- do_readtoc_43(int fd, struct cd_toc * toc_all, struct esense_reply * erp)
- {
- struct scsi_req sr;
- struct readtoc_43_cmd *rt10cp;
- struct readtoc_43_reply tocr;
- int err;
- char *toc_reply; /* toc reply from scsi bus, need to
- * be allocated */
- u_int toc_data_length,
- toc_temp_length,
- lastsec,
- currsec;
- struct rtr_desc *desc; /* pointer to traverse through *toc_reply */
- int nrecords, /* number of desc blocks info in toc */
- nrectemp,
- i,
- track,
- lasttrack;
-
- /*
- * First zero most everything in the cd_toc parameter, except the times.
- * Note the time variables are really unsigned integers..
- */
- bzero((char *)toc_all, sizeof(struct cd_toc));
- for (i = 0; i <= 100; i++) {
- toc_all->info[i].hour = -1;
- toc_all->info[i].min = -1;
- toc_all->info[i].sec = -1;
- toc_all->info[i].frame = -1;
- }
-
- bzero((char *)&sr, sizeof(sr));
- toc_reply = NULL;
-
- rt10cp = (struct readtoc_43_cmd *) & sr.sr_cdb;
- rt10cp->rt_op_code = C10OP_READTOC_43;
- rt10cp->rt_msf = 0; /* don't use msf format */
- rt10cp->rt_starttrack = 0;
- /* read only info on track 0 to find out TOC data length */
- toc_data_length = sizeof(struct readtoc_43_reply);
- SET_2BYTE_UINT(rt10cp->rt_length, toc_data_length);
-
- sr.sr_addr = (char *)&tocr;
- sr.sr_dma_max = sizeof(tocr);
- sr.sr_ioto = 5; /* time out in 5 seconds */
- sr.sr_dma_dir = SR_DMA_RD; /* read &sr.sr_addr from device */
-
- err = ioctl(fd, SDIOCSRQ, &sr);
- *erp = sr.sr_esense;
- if (err | sr.sr_io_status) {/* problem reading TOC, return */
- return err | sr.sr_io_status;
- }
- /* record first & last track, and toc data length */
- toc_all->firsttrack = tocr.h.rtr_firsttrack;
- toc_all->lasttrack = tocr.h.rtr_lasttrack;
- nrecords = tocr.h.rtr_lasttrack - tocr.h.rtr_firsttrack + 2;
- toc_data_length = nrecords * sizeof(struct rtr_desc);
- toc_temp_length = GET_2BYTE_UINT(tocr.h.rtr_datalen) - 2;
- nrectemp = toc_data_length / sizeof(struct rtr_desc);
- if (toc_temp_length > toc_data_length) {
- #ifdef CD_DEBUG2
- printf("mCD: first = %d, last = %d, nrec=%d, toc_dl = %d\n",
- tocr.h.rtr_firsttrack, tocr.h.rtr_lasttrack,
- nrecords, toc_data_length);
- printf("mCD: switch to --> nrec=%d, rtr_dl-2 = %d\n",
- nrectemp, toc_temp_length);
- #endif CD_DEBUG2
- toc_data_length = toc_temp_length;
- nrecords = nrectemp;
- } else if (toc_temp_length < toc_data_length) {
- printf("mCD: first = %d, last = %d, nrec=%d, toc_dl = %d\n",
- tocr.h.rtr_firsttrack, tocr.h.rtr_lasttrack,
- nrecords, toc_data_length);
- printf("mCD: but nrectemp=%d, rtr_dl-2 = %d !!\n",
- nrectemp, toc_temp_length);
- }
-
- /* prepare for second read toc for the whole thing */
- bzero((char *)&sr, sizeof(sr));
-
- rt10cp = (struct readtoc_43_cmd *) & sr.sr_cdb;
- rt10cp->rt_op_code = C10OP_READTOC_43;
- rt10cp->rt_msf = 1; /* want msf format */
- rt10cp->rt_starttrack = 0;
- toc_data_length += sizeof(struct rtr_header);
- SET_2BYTE_UINT(rt10cp->rt_length, toc_data_length);
-
- toc_reply = (char *)malloc(toc_data_length);
- bzero((char *)toc_reply, toc_data_length);
- sr.sr_addr = toc_reply;
- sr.sr_dma_max = toc_data_length;
- sr.sr_ioto = 5; /* time out in 5 seconds */
- sr.sr_dma_dir = SR_DMA_RD; /* read &sr.sr_addr from device */
-
- err = ioctl(fd, SDIOCSRQ, &sr);
- *erp = sr.sr_esense;
- if (err | sr.sr_io_status) {/* problem reading TOC, return */
- return err | sr.sr_io_status;
- }
- /* successfully read the whole thing, now process it. */
- desc = (struct rtr_desc *) & (toc_reply[4]); /* skip the header */
- lastsec = 0;
- lasttrack = -1;
- for (i = 0; i < nrecords; i++) {
- track = desc->rtrd_track;
- if (track == 0xaa)
- track = 100; /* lead-out area */
- if (desc->rtrd_control & DATA_TRACK)
- toc_all->ndata++;
- else if (track != 100)
- toc_all->naudio++;
- toc_all->info[track].control = desc->rtrd_control;
- toc_all->info[track].lblock = (desc->rtrd_addr.msf.hour * 3600)
- + (desc->rtrd_addr.msf.min * 60)
- + desc->rtrd_addr.msf.sec;
- toc_all->info[track].lblock = (toc_all->info[track].lblock * 75)
- + desc->rtrd_addr.msf.frame;
- toc_all->info[track].hour = desc->rtrd_addr.msf.hour;
- toc_all->info[track].min = desc->rtrd_addr.msf.min;
- toc_all->info[track].sec = desc->rtrd_addr.msf.sec;
- toc_all->info[track].frame = desc->rtrd_addr.msf.frame;
- currsec = (desc->rtrd_addr.msf.hour * 3600)
- + (desc->rtrd_addr.msf.min * 60)
- + desc->rtrd_addr.msf.sec;
- if (lasttrack > 0)
- toc_all->info[lasttrack].elapsedSec = currsec - lastsec;
- lasttrack = track;
- lastsec = currsec;
- desc++;
- }
- toc_all->info[100].elapsedSec = (toc_all->info[100].hour * 3600)
- + (toc_all->info[100].min * 60)
- + toc_all->info[100].sec;
-
- #ifdef CD_DEBUG
- /* print the table of contents to stderr */
- printf("\n start time time elapsed\n");
- for (i = toc_all->firsttrack; i <= toc_all->lasttrack; i++) {
- printf("Track %2d: %d:%02d:%02d-%02d %c %02d:%02d\n", i,
- toc_all->info[i].hour, toc_all->info[i].min,
- toc_all->info[i].sec,
- toc_all->info[i].frame,
- toc_all->info[i].control & DATA_TRACK ? 'D' : 'A',
- toc_all->info[i].elapsedSec / 60,
- toc_all->info[i].elapsedSec % 60);
- }
- printf("Track LO: %d:%02d:%02d-%02d %c\n",
- toc_all->info[100].hour, toc_all->info[100].min,
- toc_all->info[100].sec,
- toc_all->info[100].frame,
- toc_all->info[100].control & DATA_TRACK ? 'D' : 'A');
- #endif
-
- if (toc_reply != NULL)
- free(toc_reply);
- return err | sr.sr_io_status;
- }
-
-
- /**************************************************************************
- * do_readsubchannel_42
- *
- * This is only here for reference purposes. Almost all programs
- * interested in the information from readsubchannel should be using
- * routines like do_readcurrentposition_42 and do_readmediacatnum_42.
- */
- int
- do_readsubchannel_42(int fd, int msf, int subq, int page, int track,
- struct sc_reply * scrp, struct esense_reply * erp)
- {
- struct scsi_req sr;
- struct read_subchannel_42_cmd *rscp;
- int err;
-
- bzero((char *)&sr, sizeof(sr));
-
- rscp = (struct read_subchannel_42_cmd *) & sr.sr_cdb;
- rscp->rsc_op_code = C10OP_READSUBCHANNEL_42;
- rscp->rsc_msf = msf;
- rscp->rsc_subq = subq;
- rscp->rsc_dformat = page;
- rscp->rsc_track = track;
- SET_2BYTE_UINT(rscp->rsc_length, sizeof(struct sc_reply));
-
- sr.sr_addr = (char *)scrp;
- sr.sr_dma_max = sizeof(struct sc_reply);
- sr.sr_ioto = 5; /* time out in 5 seconds */
- sr.sr_dma_dir = SR_DMA_RD;
-
- err = ioctl(fd, SDIOCSRQ, &sr);
- *erp = sr.sr_esense;
- return err | sr.sr_io_status;
- }
-
-
- /**************************************************************************
- * do_readcurrentposition_42
- *
- * This is really the "read sub-channel data" command with a few of
- * the fields automatically filled in.
- */
- int
- do_readcurrentposition_42(int fd, struct rsc_cur_pos_reply * curpos,
- struct esense_reply * erp)
- {
- struct scsi_req sr;
- struct sc_reply scrp;
- struct read_subchannel_42_cmd *rscp;
- u_int tempUint;
- int err;
-
- bzero((char *)&sr, sizeof(sr));
- bzero((char *)&scrp, sizeof(scrp));
-
- rscp = (struct read_subchannel_42_cmd *) & sr.sr_cdb;
- rscp->rsc_op_code = C10OP_READSUBCHANNEL_42;
- rscp->rsc_msf = 1; /* want MSF (not LBA) format for times */
- rscp->rsc_subq = 1; /* want to get Q subchannel data */
- rscp->rsc_dformat = 1; /* want page 1 of Q subchannel data */
- rscp->rsc_track = 0; /* track is irrelevent for page 1 req */
- SET_2BYTE_UINT(rscp->rsc_length, sizeof(struct sc_reply));
-
- sr.sr_addr = (char *)&scrp;
- sr.sr_dma_max = sizeof(struct sc_reply);
- sr.sr_ioto = 5; /* time out in 5 seconds */
- sr.sr_dma_dir = SR_DMA_RD;
-
- err = ioctl(fd, SDIOCSRQ, &sr);
- *erp = sr.sr_esense;
- curpos->track = scrp.u.u_scr_cur_pos.sc1_track;
- curpos->index = scrp.u.u_scr_cur_pos.sc1_index;
- curpos->rsc_control = scrp.u.u_scr_cur_pos.sc1_control;
- curpos->rsc_audio_status = scrp.scr_header.sch_astatus;
-
- if (rscp->rsc_msf == 1) { /* ie, msf formatted times */
- curpos->abs_logical_block = scrp.u.u_scr_cur_pos.sc1_abs_addr.msf.sec
- + (scrp.u.u_scr_cur_pos.sc1_abs_addr.msf.min * 60)
- + (scrp.u.u_scr_cur_pos.sc1_abs_addr.msf.hour * 3600);
- curpos->abs_logical_block = (curpos->abs_logical_block * 75)
- + scrp.u.u_scr_cur_pos.sc1_abs_addr.msf.frame;
- curpos->abs_hour = scrp.u.u_scr_cur_pos.sc1_abs_addr.msf.hour;
- curpos->abs_min = scrp.u.u_scr_cur_pos.sc1_abs_addr.msf.min;
- curpos->abs_sec = scrp.u.u_scr_cur_pos.sc1_abs_addr.msf.sec;
- curpos->abs_frame = scrp.u.u_scr_cur_pos.sc1_abs_addr.msf.frame;
- if (curpos->abs_min >= 60) {
- curpos->abs_hour++;
- curpos->abs_min -= 60;
- }
- curpos->rel_logical_block = scrp.u.u_scr_cur_pos.sc1_rel_addr.msf.sec
- + (scrp.u.u_scr_cur_pos.sc1_rel_addr.msf.min * 60)
- + (scrp.u.u_scr_cur_pos.sc1_rel_addr.msf.hour * 3600);
- curpos->rel_logical_block = (curpos->rel_logical_block * 75)
- + scrp.u.u_scr_cur_pos.sc1_rel_addr.msf.frame;
- curpos->rel_hour = scrp.u.u_scr_cur_pos.sc1_rel_addr.msf.hour;
- curpos->rel_min = scrp.u.u_scr_cur_pos.sc1_rel_addr.msf.min;
- curpos->rel_sec = scrp.u.u_scr_cur_pos.sc1_rel_addr.msf.sec;
- curpos->rel_frame = scrp.u.u_scr_cur_pos.sc1_rel_addr.msf.frame;
- if (curpos->rel_min >= 60) {
- curpos->rel_hour++;
- curpos->rel_min -= 60;
- }
- } else { /* ie, lba formatted times */
- tempUint = GET_4BYTE_UINT(scrp.u.u_scr_cur_pos.sc1_abs_addr.lba.lblock);
- curpos->abs_logical_block = tempUint;
- curpos->abs_frame = tempUint % 75;
- curpos->abs_sec = tempUint / 75;
- curpos->abs_min = curpos->abs_sec / 60;
- curpos->abs_sec = curpos->abs_sec % 60;
- if (curpos->abs_min >= 60) {
- curpos->abs_hour++;
- curpos->abs_min -= 60;
- }
- tempUint = GET_4BYTE_UINT(scrp.u.u_scr_cur_pos.sc1_rel_addr.lba.lblock);
- curpos->rel_logical_block = tempUint;
- curpos->rel_frame = tempUint % 75;
- curpos->rel_sec = tempUint / 75;
- curpos->rel_min = curpos->rel_sec / 60;
- curpos->rel_sec = curpos->rel_sec % 60;
- if (curpos->rel_min >= 60) {
- curpos->rel_hour++;
- curpos->rel_min -= 60;
- }
- }
-
- return err | sr.sr_io_status;
- }
-
-
- /**************************************************************************
- * do_readmediacatnum_42
- *
- * This is really the "read sub-channel data" command with a few of
- * the fields automatically filled in.
- */
- int
- do_readmediacatnum_42(int fd, struct rsc_media_catnum_reply * catnum,
- struct esense_reply * erp)
- {
- struct scsi_req sr;
- struct sc_reply scrp;
- struct read_subchannel_42_cmd *rscp;
- int err;
-
- bzero((char *)&sr, sizeof(sr));
- bzero((char *)&scrp, sizeof(scrp));
-
- rscp = (struct read_subchannel_42_cmd *) & sr.sr_cdb;
- rscp->rsc_op_code = C10OP_READSUBCHANNEL_42;
- rscp->rsc_msf = 0; /* MSF format is irrelevent for this */
- rscp->rsc_subq = 1; /* want to get Q subchannel data */
- rscp->rsc_dformat = 2; /* want page 2 of Q subchannel data */
- rscp->rsc_track = 0; /* track is irrelevent for page 2 req */
- SET_2BYTE_UINT(rscp->rsc_length, sizeof(struct sc_reply));
-
- sr.sr_addr = (char *)&scrp;
- sr.sr_dma_max = sizeof(struct sc_reply);
- sr.sr_ioto = 10; /* time out in 10 seconds */
- sr.sr_dma_dir = SR_DMA_RD;
-
- err = ioctl(fd, SDIOCSRQ, &sr);
- *erp = sr.sr_esense;
- catnum->catnum_isSet = scrp.u.u_scr_med_cat.sc2_mcval;
- memcpy(catnum->media_catnum, scrp.u.u_scr_med_cat.sc2_med_cat, 15);
-
- /*
- * note that many CDs have mcval set on, but the media-cat# is zero... Also
- * note that different drives return the media-cat# in different formats...
- */
- bzero((char *)&scrp.u.u_scr_med_cat.sc2_med_cat, 15); /* = no catnum */
- if (!memcmp(catnum->media_catnum, scrp.u.u_scr_med_cat.sc2_med_cat, 15))
- catnum->catnum_isSet = 0;
- if (!memcmp(catnum->media_catnum, "000000000000000", 15))
- catnum->catnum_isSet = 0;
-
- return err | sr.sr_io_status;
- }
-
-
- /**************************************************************************
- * do_playbackstatus_c4
- *
- * Find out the position and status (playing, paused, whatever) of
- * the CD drive. Also picks up the current volume settings. Note
- * that this is probably Sony-specific.
- */
- int
- do_playbackstatus_c4(int fd, struct pb_status_reply * pbstatus,
- struct esense_reply * erp)
- {
- struct scsi_req sr;
- struct playback_statuscontrol_cmd *pbcp;
- struct playback_c4c9_data pbdata;
- u_int tempUint;
- int err;
-
- bzero((char *)&sr, sizeof(sr));
-
- pbcp = (struct playback_statuscontrol_cmd *) & sr.sr_cdb;
- pbcp->pb_opcode = C10OP_PLAYBACKSTATUS_C4;
- SET_2BYTE_UINT(pbcp->pb_length, sizeof(struct playback_c4c9_data));
-
- bzero((char *)&pbdata, sizeof(pbdata));
- sr.sr_addr = (char *)&pbdata;
- sr.sr_dma_max = sizeof(struct playback_c4c9_data);
- sr.sr_ioto = 1; /* time out in 1 second */
- sr.sr_dma_dir = SR_DMA_RD;
-
- err = ioctl(fd, SDIOCSRQ, &sr);
- *erp = sr.sr_esense;
-
- /*
- * copy information from platform-specific (bigendian) layout to one that
- * matches the current platform
- */
- bzero((char *)pbstatus, sizeof(struct pb_status_reply));
- pbstatus->pbs_audio_status = pbdata.pbd_audio_status;
- pbstatus->pbs_ch0_sel = pbdata.pbd_ch0_sel;
- pbstatus->pbs_ch0_vol = pbdata.pbd_ch0_vol;
- pbstatus->pbs_ch1_sel = pbdata.pbd_ch1_sel;
- pbstatus->pbs_ch1_vol = pbdata.pbd_ch1_vol;
- pbstatus->pbs_ch2_sel = pbdata.pbd_ch2_sel;
- pbstatus->pbs_ch2_vol = pbdata.pbd_ch2_vol;
- pbstatus->pbs_ch3_sel = pbdata.pbd_ch3_sel;
- pbstatus->pbs_ch3_vol = pbdata.pbd_ch3_vol;
-
- /* the cd-address is returned in both addressing formats */
- if (pbdata.pbd_lbamsf == 1) { /* ie, msf formatted times */
- if (pbdata.pbd_cd_addr.msf.min == 255) {
- /* if min = 255, then we're really before the */
- /* start of the first track... */
- pbdata.pbd_cd_addr.msf.min = 0;
- pbdata.pbd_cd_addr.msf.sec = 0;
- pbdata.pbd_cd_addr.msf.frame = 75 - pbdata.pbd_cd_addr.msf.frame;
- }
- pbstatus->pbs_logical_block = pbdata.pbd_cd_addr.msf.sec
- + (pbdata.pbd_cd_addr.msf.min * 60)
- + (pbdata.pbd_cd_addr.msf.hour * 3600);
- pbstatus->pbs_logical_block = (pbstatus->pbs_logical_block * 75)
- + pbdata.pbd_cd_addr.msf.frame;
- pbstatus->pbs_hour = pbdata.pbd_cd_addr.msf.hour;
- pbstatus->pbs_min = pbdata.pbd_cd_addr.msf.min;
- pbstatus->pbs_sec = pbdata.pbd_cd_addr.msf.sec;
- pbstatus->pbs_frame = pbdata.pbd_cd_addr.msf.frame;
- if (pbstatus->pbs_min >= 60) {
- pbstatus->pbs_hour++;
- pbstatus->pbs_min -= 60;
- }
- } else { /* ie, lba formatted times */
- tempUint = GET_4BYTE_UINT(pbdata.pbd_cd_addr.lba.lblock);
- pbstatus->pbs_logical_block = tempUint;
- pbstatus->pbs_frame = tempUint % 75;
- pbstatus->pbs_sec = tempUint / 75;
- pbstatus->pbs_min = pbstatus->pbs_sec / 60;
- pbstatus->pbs_sec = pbstatus->pbs_sec % 60;
- if (pbstatus->pbs_min == 255) {
- /* if min = 255, then we're really before the */
- /* start of the first track... */
- pbstatus->pbs_min = 0;
- pbstatus->pbs_sec = 0;
- pbstatus->pbs_frame = 75 - pbstatus->pbs_frame;
- pbstatus->pbs_logical_block = pbstatus->pbs_frame;
- }
- if (pbstatus->pbs_min >= 60) {
- pbstatus->pbs_hour++;
- pbstatus->pbs_min -= 60;
- }
- }
-
- return err | sr.sr_io_status;
- }
-
-
- /**************************************************************************
- * do_playbackvolume_c9
- *
- * Change the current volume settings, using the playback control
- * command (which is probably Sony-specific).
- */
- int
- do_playbackvolume_c9(int fd, int leftVolume, int rightVolume,
- struct esense_reply * erp)
- {
- struct scsi_req sr;
- struct playback_statuscontrol_cmd *pbcp;
- struct playback_c4c9_data pbdata;
- int err;
-
- bzero((char *)&sr, sizeof(sr));
-
- pbcp = (struct playback_statuscontrol_cmd *) & sr.sr_cdb;
- pbcp->pb_opcode = C10OP_PLAYBACKCONTROL_C9;
- SET_2BYTE_UINT(pbcp->pb_length, sizeof(struct playback_c4c9_data));
-
- bzero((char *)&pbdata, sizeof(pbdata));
- pbdata.pbd_ch0_sel = 1;
- pbdata.pbd_ch0_vol = leftVolume;
- pbdata.pbd_ch1_sel = 2;
- pbdata.pbd_ch1_vol = rightVolume;
-
- sr.sr_addr = (char *)&pbdata;
- sr.sr_dma_max = sizeof(struct playback_c4c9_data);
- sr.sr_ioto = 1; /* time out in 1 second */
- sr.sr_dma_dir = SR_DMA_WR;
-
- err = ioctl(fd, SDIOCSRQ, &sr);
- *erp = sr.sr_esense;
- return err | sr.sr_io_status;
- }
-
-
- /**************************************************************************
- * do_modesense_pc_E
- *
- * This is just the do_modesense command from scsi_commands, except
- * that it's setup to return page-code E in particular. Page-code E
- * is the one for CD-ROM Audio Control parameters. Declarations of
- * some structs are also redone (and in cd_cmdsint.h) to make them
- * more platform-independent.
- */
- int
- do_modesense_pc_E(int fd, struct cd_volset_reply * volset, struct esense_reply * erp)
- {
- struct scsi_req sr;
- struct mode_sense_select_cmd *mscp;
- struct mode_sense_select_reply msrp;
- int err;
-
- bzero((char *)&sr, sizeof(sr));
- bzero((char *)&msrp, sizeof(msrp));
-
- mscp = (struct mode_sense_select_cmd *) & sr.sr_cdb;
- mscp->msc_opcode = C6OP_MODESENSE;
- mscp->msc_lun = 0;
- mscp->msc_pcf = 0; /* report current values */
- mscp->msc_page = 0x0E;
- mscp->msc_len = sizeof(msrp);
-
- sr.sr_addr = (char *)&msrp;
- sr.sr_dma_max = sizeof(msrp);
- sr.sr_ioto = 50; /* using an extended timeout */
- sr.sr_dma_dir = SR_DMA_RD; /* read &sr.sr_addr from device */
-
- err = ioctl(fd, SDIOCSRQ, &sr);
- *erp = sr.sr_esense;
-
- /*
- * copy information from platform-specific (bigendian) layout to one that
- * matches the current platform
- */
- bzero((char *)volset, sizeof(struct cd_volset_reply));
- volset->ch0_sel = msrp.u.u_msr_pcE.pce_ch0_sel;
- volset->ch0_vol = msrp.u.u_msr_pcE.pce_ch0_vol;
- volset->ch1_sel = msrp.u.u_msr_pcE.pce_ch1_sel;
- volset->ch1_vol = msrp.u.u_msr_pcE.pce_ch1_vol;
- volset->ch2_sel = msrp.u.u_msr_pcE.pce_ch2_sel;
- volset->ch2_vol = msrp.u.u_msr_pcE.pce_ch2_vol;
- volset->ch3_sel = msrp.u.u_msr_pcE.pce_ch3_sel;
- volset->ch3_vol = msrp.u.u_msr_pcE.pce_ch3_vol;
-
- return err | sr.sr_io_status;
- }
-
-
- /**************************************************************************
- * do_modeselect_pc_E
- *
- * This is basically just the do_modesense_pc_E command reversed,
- * such that CD volume settings are being set instead of sensed.
- */
- int
- do_modeselect_pc_E(int fd, int leftVolume, int rightVolume, struct esense_reply * erp)
- {
- struct scsi_req sr;
- struct mode_sense_select_cmd *mscp;
- struct mode_select_alt_reply msarp;
- int err;
-
- bzero((char *)&sr, sizeof(sr));
-
- mscp = (struct mode_sense_select_cmd *) & sr.sr_cdb;
- mscp->msc_opcode = C6OP_MODESELECT;
- mscp->msc_lun = 0;
- mscp->msc_len = sizeof(msarp);
-
- sr.sr_addr = (char *)&msarp;
- sr.sr_dma_max = sizeof(msarp);
- sr.sr_ioto = 50; /* using an extended timeout */
- sr.sr_dma_dir = SR_DMA_WR; /* write &sr.sr_addr to device */
-
- bzero((char *)&msarp, sizeof(msarp));
- msarp.msar_plh.plh_blkdesclen = 0; /* using alternate form, with no
- * block descriptor */
- msarp.u.u_msar_pcE.pce_pagecode = 0x0E;
- msarp.u.u_msar_pcE.pce_parlen = 0x0E;
- msarp.u.u_msar_pcE.pce_immd = YES;
- msarp.u.u_msar_pcE.pce_ch0_sel = 1;
- msarp.u.u_msar_pcE.pce_ch0_vol = leftVolume;
- msarp.u.u_msar_pcE.pce_ch1_sel = 2;
- msarp.u.u_msar_pcE.pce_ch1_vol = rightVolume;
-
- err = ioctl(fd, SDIOCSRQ, &sr);
-
- *erp = sr.sr_esense;
-
- return err | sr.sr_io_status;
- }
-